package com.hundsun.cprs.yyt.service.match.core.command;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.alibaba.fastjson.JSON;
import com.hundsun.cprs.yyt.service.match.core.Matching;
import com.hundsun.cprs.yyt.service.match.core.queue.EntrustQueue;
import com.hundsun.cprs.yyt.service.match.core.queue.PriceCell;
import com.hundsun.cprs.yyt.service.match.domain.DefaultTradeMatch;
import com.hundsun.cprs.yyt.service.match.domain.TradeEntrust;
import com.hundsun.cprs.yyt.service.match.domain.TradeMatchDetail;
import com.hundsun.cprs.yyt.service.match.service.ServiceLocate;
import com.hundsun.cprs.yyt.util.TradeEntrustBeanUtil;

/**
 * 连续匹配指令
 * 
 */
public class DefaultMatchCommand extends BaseCommand implements MatchingCommand {
    private static final Log logger = LogFactory.getLog(DefaultMatchCommand.class);

    protected TradeEntrust entrust;

    public DefaultMatchCommand(TradeEntrust entrust) {
        super();
        this.entrust = entrust;
    }
    
    @Override
    public void perform(Matching matching, Executor executor){
        final DefaultTradeMatch match = new DefaultTradeMatch(matching.getTradeCenter().getStockCode());
        long suitedAmount = 0L;// 匹配成功的数量
        final List<TradeEntrust> expireEntrust = new ArrayList<TradeEntrust>();
        while (true) {
            long amount = entrust.getSurplusEntrustAmount();
            PriceCell pc = entrust.isBuy() ? matching.getSellQueue().getHeader() : matching.getBuyQueue().getHeader();
            if (pc == null) {
                // 对方没有挂单
                logger.debug("1没有可匹配的" + (entrust.isBuy()?"挂卖单":"挂买单"));
                break;
            }
            TradeEntrust bestEntrust = checkAndReturnBestEntrust(pc.getEntrustQueue(),expireEntrust);
            if (bestEntrust == null) {
                // 对方挂单基本都已过期，自动撤销
                logger.debug("2没有可匹配的" + (entrust.isBuy()?"挂卖单":"挂买单"));
                break;
            }
            //定价,以买家订单价格优先成交
            long bestPrice = entrust.isBuy() ? entrust.getEntrustPrice() : bestEntrust.getEntrustPrice();
            // 找到和价格对应的买(卖)单
            long bestEntrustAmount = bestEntrust.getSurplusEntrustAmount();
            if (amount <= bestEntrustAmount) {// 订单全部成交,匹配结束
                entrust.subEntrustAmount(amount);
                bestEntrust.subEntrustAmount(amount);// 大家都扣掉成交的量
                match.addMatchDetail(new TradeMatchDetail(entrust, amount, bestPrice, false));
                match.addMatchDetail(new TradeMatchDetail(bestEntrust, amount, bestPrice, true));
                if (entrust.isBuy()) {
                    matching.getQuotes().reduceSellingAmount(bestEntrust.getFundAccount(), amount);
                } else {
                    matching.getQuotes().reduceBuyingAmount(bestEntrust.getFundAccount(), amount);
                }
                suitedAmount += amount;
                if (bestEntrust.isEntrustAmountAllMatch()) {
                    if (entrust.isBuy()) {
                        matching.getSellQueue().removeEntrust(bestEntrust);
                    } else {
                        matching.getBuyQueue().removeEntrust(bestEntrust);
                    }
                }
                break;
            } else {// 订单还有剩余,继续匹配
                entrust.subEntrustAmount(bestEntrustAmount);
                bestEntrust.subEntrustAmount(bestEntrustAmount);// 大家都扣掉成交的量
                match.addMatchDetail(new TradeMatchDetail(entrust, bestEntrustAmount, bestPrice, false));
                match.addMatchDetail(new TradeMatchDetail(bestEntrust, bestEntrustAmount, bestPrice, true));
                if (entrust.isBuy()) {
                    matching.getQuotes().reduceSellingAmount(bestEntrust.getFundAccount(), bestEntrustAmount);
                } else {
                    matching.getQuotes().reduceBuyingAmount(bestEntrust.getFundAccount(), bestEntrustAmount);
                }
                
                suitedAmount += bestEntrustAmount;
                if (entrust.isBuy()) {
                    matching.getSellQueue().removeEntrust(bestEntrust);
                } else {
                    matching.getBuyQueue().removeEntrust(bestEntrust);
                }
            }
        }

        if (logger.isDebugEnabled()) {
            logger.debug("ContinuousAuction suited amount:" + suitedAmount);
        }

        final boolean haveSuite = suitedAmount > 0;

        if (haveSuite) {// 下单有成交
            // 得到撮合序号
            // match.setMatchSeq(matching.getQuotes().getTradeSequence());
            if (logger.isDebugEnabled()) {
                logger.debug("ContinuousAuction Match Sequence:" + match.getMatchSeq());
            }
            match.calculate();
        }

        // 还有剩下的
        if (!entrust.isEntrustAmountAllMatch()) {
            if (entrust.isLastEntrustPaste()) {
                // 剩下的挂单
                if (haveSuite) {
                    // 改成部成
                    entrust.setEntrustStatus(TradeEntrust.EntrustStatusPartDealt);
                } else {
                    // 挂单状态
                    entrust.setEntrustStatus(TradeEntrust.EntrustStatusCommited);
                }
                if (entrust.isBuy()) {
                    matching.getBuyQueue().placeEntrust(entrust);
                    matching.getQuotes().addBuyingAmount(entrust.getFundAccount(),entrust.getSurplusEntrustAmount());
                } else {
                    matching.getSellQueue().placeEntrust(entrust);
                    matching.getQuotes().addSellingAmount(entrust.getFundAccount(),entrust.getSurplusEntrustAmount());
                }
            } else {
                // 剩下的撤销
                if (haveSuite) {
                    // 状态改为部撤
                    entrust.setEntrustStatus(TradeEntrust.EntrustStatusPartCanceled);
                } else {
                    // 改为已撤
                    entrust.setEntrustStatus(TradeEntrust.EntrustStatusCanceled);
                }
            }
        }
        
        if (!expireEntrust.isEmpty()) {
            //过期移除的订单，减少统计
            for(TradeEntrust entrust : expireEntrust){
                if (entrust.isBuy()) {
                    matching.getQuotes().reduceBuyingAmount(entrust.getFundAccount(), entrust.getSurplusEntrustAmount());
                } else {
                    matching.getQuotes().reduceSellingAmount(entrust.getFundAccount(), entrust.getSurplusEntrustAmount());
                }
            }
        }

        //匹配成交后异步处理
        //final boolean cancel = !entrust.isEntrustAmountAllMatch() && entrust.isLastEntrustCancel();
        //final boolean pasteEntrust = !entrust.isEntrustAmountAllMatch() && entrust.isLastEntrustPaste();
        executor.execute(new Runnable() {
            public void run() {
                System.out.println("委托详情：" + JSON.toJSONString(entrust));
                if (haveSuite) {
                    System.out.println("成交详情：" + JSON.toJSONString(match));
                    // 保存交易数据
                    ServiceLocate.getTradeMatchService().updateAfterMatch(TradeEntrustBeanUtil.copyPropertiesFrom(match));
                }
                if (!expireEntrust.isEmpty()) {
                    if (logger.isInfoEnabled()) {
                        logger.info("有过期订单，更新订单为已撤销" + expireEntrust.size());
                    }
                    ServiceLocate.getTradeMatchService().cancelEntrust(TradeEntrustBeanUtil.copyPropertiesFrom(expireEntrust));
                }
            }
        });
    }
    
    
    private TradeEntrust checkAndReturnBestEntrust(EntrustQueue queue,List<TradeEntrust> expireEntrust){
        while(true){
            TradeEntrust bestEntrust = queue.getHeader();
            
            //未过期的订单返回
            if (bestEntrust != null && 
                bestEntrust.getExpireDate() != null && 
                System.currentTimeMillis() > bestEntrust.getExpireDate().getTime()) {
                
                queue.removeEntrust(bestEntrust);
                long entrustAmount = bestEntrust.getEntrustAmount();
                long surplusEntrustAmount = bestEntrust.getSurplusEntrustAmount();
                if (entrustAmount > surplusEntrustAmount) {
                    bestEntrust.setEntrustStatus(TradeEntrust.EntrustStatusPartCanceled);
                } else {
                    bestEntrust.setEntrustStatus(TradeEntrust.EntrustStatusCanceled);
                }
                expireEntrust.add(bestEntrust);
                continue;
            }
            return bestEntrust;
        }
    }
}
